/*package gm2;
object bla{
  
trait Generic[gg <: TypeFun1]  {
  type MyRep[t] = Rep[gg, t] 
  type Res[t] = gg{type a=t}
           
  def unit: Res[Unit]
  def plus[aa, b](implicit c1: aa=>MyRep[aa], c2: b=>MyRep[b]): Res[Plus[aa, b]]
  ...
    
trait Rep[g <: TypeFun1, t] {           
  type Res[t] = g{type a=t}        
  def rep: Res[t] // TODO translate constraint Generic g  (not necessary??)
}

trait Convs {
  type g <: TypeFun1
  type MyRep[t] = Rep[g, t]                 

  val generic: Generic[g]
  def mr[t](f: Generic[g]=>g{type a=t}) = new MyRep[t]{def rep: Res[t]=f(generic)}    
}

trait CoreConvs extends Convs { 
  implicit def unit2rep(u: Unit): MyRep[Unit] = mr (.unit)
  implicit def plus2rep[t, u](p: Plus[t, u])(implicit c1: t=>MyRep[t], c2: u=>MyRep[u]): MyRep[Plus[t, u]]  
      = mr (.plus(c1, c2))
  ...
    
class ShowBin extends Generic[TShowBin] {
  def unit = tsb ((x: Unit) => Nil) 
  def plus[aa, b](implicit c1: aa=>MyRep[aa], c2: b=>MyRep[b]) = tsb (
      (x: Plus[aa, b]) => x match {
        case Inl(el) => _0 :: showBin(el)
        case Inr(el) => _1 :: showBin(el)
      }) 

  def showBin[t](x: t)(implicit c: t=>MyRep[t]): Bin = x.rep.apply(x) 
  def tsb[aa](f: aa => Bin) = new TShowBin{type a=aa; val apply = f} 
  

      
  def pair[aa, b](implicit c1: aa=>MyRep[aa], c2: b=>MyRep[b]) = tsb (
      (x: Pair[aa, b]) => showBin(x._1) ::: showBin(x._2))
  
  def datatype[aa, b](iso: Iso[aa,b])(implicit c1: aa=>MyRep[aa]) = tsb (
      (x: b) => showBin(iso.fromData(x)))
  
  def char = tsb ((x: Char) => bits(7,x))
  def int = tsb ((x: Int) => bits(16,x))
}



trait ListConv extends CoreConvs{
  def fromList[t](l: List[t]): Plus[Unit, Pair[t, List[t]]] = l match {
    case Nil => Inl(())
    case x :: xs => Inr(Pair(x, xs))
  }
  
  def toList[t](l: Plus[Unit, Pair[t, List[t]]]): List[t] = l match {
    case Inl(())=> Nil 
    case Inr(Pair(x, xs)) => x :: xs 
  }
  
  implicit def list2rep[t](l: List[t])(implicit c: t=>MyRep[t]): MyRep[List[t]] 
    = mr (.datatype(Iso(fromList[t], toList[t])))  // TODO: have to supply [t], why?
}     

def bits(n: Int, x: Int): Bin = if(n==0) Nil else {if((x&1)==1) _1 else _0} :: bits(n-1,x>>1)

type Bin = List[Bit]
trait Bit
  case object _0 extends Bit
  case object _1 extends Bit
                                
trait TShowBin extends TypeFun1{
  val apply: a => Bin 
}


trait TypeFun1 {
  type a
}


trait Plus[a,b]
  case class Inl[a,b](el: a) extends Plus[a,b]
  case class Inr[a,b](el: b) extends Plus[a,b]

case class Iso[t,dt](fromData: dt=>t, toData: t=>dt)


}
// testpad:
// {val sb = new ShowBin(); import sb.convs._; sb.showBin(3)}
// {val sb = new ShowBin(); import sb.convs._; sb.showBin(List(3,5))}
//{val sb = new ShowBin(); import sb.convs._; sb.showBin("Lisa".toList)}
//{val sb = new ShowBin(); import sb.convs._; sb.showBin("Lisa")} // --> string2seq is not chained with list2rep
*/